import classNames from 'classnames';
import React from 'react';
import {
  IBasicProps,
  IComponentProps,
  IGeneratorProps,
  ITagType,
  layoutPrefix,
} from './typings';

import './layout.less';

/** 判断是否含有Sider子组件 */
function judeSider(children: React.ReactNode) {
  let hasSider = false;

  React.Children.forEach(children, (child) => {
    if (React.isValidElement(child) && typeof child.type !== 'string') {
      if (child.type === SectionSider) {
        hasSider = true;
      }
    }
  });

  return hasSider;
}

export const LayoutContext = /*#__PURE__*/ React.createContext({
  siderHook: {
    addSider: () => {
      return null;
    },
    removeSider: () => {
      return null;
    },
  },
});

/** 获取布局前缀 */
function getPrefixCls(
  suffixCls?: string,
  customizePrefixCls?: string
) {
  if (customizePrefixCls) {
    return customizePrefixCls;
  }

  return suffixCls ? `${layoutPrefix}-${suffixCls}` : layoutPrefix;
}

/** 布局生成器 */
export function generator(genProps: IGeneratorProps) {
  const { suffixCls, tagName = 'div', displayName } = genProps;

  return function (BasicComponent: ITagType) {
    const Adapter: IComponentProps = React.forwardRef(
      (props: IBasicProps, ref) => {
        const customizePrefixCls = props.prefixCls;
        const prefixCls = getPrefixCls(suffixCls, customizePrefixCls);

        return React.createElement(
          BasicComponent,
          Object.assign(
            {
              ref,
              prefixCls,
              tagName,
            },
            props,
          ),
        );
      },
    );

    if (process.env.NODE_ENV !== 'production') {
      Adapter.displayName = displayName;
    }

    return Adapter;
  };
}

/** 基本布局，包裹层，可包含侧栏 */
export const BasicLayout = (isLayout?: boolean) => {
  return React.forwardRef((props: IBasicProps, ref) => {
    const {
      prefixCls,
      className,
      children,
      tagName = 'div',
      direction,
      bordered,
      textAlign,
      abs,
      hasSider,
      gap,
      style,
      ...rest
    } = props;

    const classString = classNames(prefixCls, className, {
      [`is-horizontal`]: direction === 'horizontal',
      [`is-border`]: bordered,
      [`is-border-${bordered}`]: bordered && bordered !== true,
      [`is-${textAlign}`]: textAlign && textAlign,
      [`is-abs`]: isLayout && abs,
      [`has-sider`]:
        isLayout &&
        (typeof hasSider === 'boolean' ? hasSider : judeSider(children)),
    });

    return React.createElement(
      tagName,
      Object.assign(
        {
          ref,
          className: classString,
          style: { ...style, gap },
        },
        rest,
      ),
      children,
    );
  });
};

const Section = generator({
  suffixCls: 'layout',
  tagName: 'section',
  displayName: 'Layout',
})(BasicLayout(true));

export const SectionHeader = generator({
  suffixCls: 'layout-header',
  tagName: 'header',
  displayName: 'SectionHeader',
})(BasicLayout());

export const SectionFooter = generator({
  suffixCls: 'layout-footer',
  tagName: 'footer',
  displayName: 'SectionFooter',
})(BasicLayout());

export const SectionContent = generator({
  suffixCls: 'layout-content',
  tagName: 'main',
  displayName: 'SectionContent',
})(BasicLayout());

export const SectionSider = generator({
  suffixCls: 'layout-sider',
  tagName: 'aside',
  displayName: 'SectionSider',
})(BasicLayout());

export default Section;
